<!DOCTYPE html>
<html lang="en">
<head>
<title>Oimo.js Compound2</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=11" />
<link rel="shortcut icon" href="./assets/img/favicon.ico">
<link rel="stylesheet" href="css/demo.css">

<script src="js/demo.js"></script>
<script src="js/libs/three.min.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="../build/oimo.js"></script>

</head>
<body>
<canvas id="canvas"></canvas>
<div id='interface'>
    <input type="button" value="demo 1" onClick=populate(1)>
    <input type="button" value="demo 2" onClick=populate(2)>
    <input type="number" name="quantity" min="10" max="2000" value="400"  id='MaxNumber'>
    <input type="submit" onClick=populate()>
    <input type="number" name="gravity" min="-20" max="20" value="-10" id='gravity' onChange=gravity() >
</div>
<div id='info'></div>
<img style="position: absolute; top: 0; right: 0; border: 0;" src="assets/img/ribbon.png"></a>
<a id="ribbon" href="https://github.com/lo-th/Oimo.js"></a>      
<script>
    demolink();

    var isMobile = false;
    var antialias = true;

    // three var
    var camera, scene, light, renderer, canvas, controls;
    var meshs = [];
    var grounds = [];
    var geoBox, geoCyl, buffgeoSphere, buffgeoBox;
    var matBox, matSphere, matBoxSleep, matSphereSleep, matGround;
    var types, sizes, positions, chairGeometry, capsuleGeometry;
    var ToRad = 0.0174532925199432957;

    //oimo var
    var world = null;
    var bodys = null;
    var infos;
    var type = 1;

    init();
    loop();

    function init() {
        var n = navigator.userAgent;
        if (n.match(/Android/i) || n.match(/webOS/i) || n.match(/iPhone/i) || n.match(/iPad/i) || n.match(/iPod/i) || n.match(/BlackBerry/i) || n.match(/Windows Phone/i)){ isMobile = true;  antialias = false; }

        infos = document.getElementById("info");

        canvas = document.getElementById("canvas");

        camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 5000 );
        camera.position.set( 0, 160, 400 );

        controls = new THREE.OrbitControls( camera, canvas );
        controls.target.set(0, 20, 0);
        controls.update();;

        scene = new THREE.Scene();

        renderer = new THREE.WebGLRenderer({ canvas:canvas, precision: "mediump", antialias:antialias });
        renderer.setSize( window.innerWidth, window.innerHeight );

        var materialType = 'MeshBasicMaterial';

        if(!isMobile){
            scene.add( new THREE.AmbientLight( 0x3D4143 ) );
            light = new THREE.DirectionalLight( 0xffffff , 1);
            light.position.set( 300, 1000, 500 );
            light.target.position.set( 0, 0, 0 );
            light.castShadow = true;
            var d = 300;
            light.shadow.camera = new THREE.OrthographicCamera( -d, d, d, -d,  500, 1600 );
            light.shadow.bias = 0.0001;
            light.shadow.mapSize.width = light.shadow.mapSize.height = 1024;
            scene.add( light );

            materialType = 'MeshPhongMaterial';

            renderer.shadowMap.enabled = true;
            renderer.shadowMap.type = THREE.PCFShadowMap;//THREE.BasicShadowMap;
        }

        // background
        var buffgeoBack = new THREE.BufferGeometry();
        buffgeoBack.fromGeometry( new THREE.IcosahedronGeometry(3000,2) );
        var back = new THREE.Mesh( buffgeoBack, new THREE.MeshBasicMaterial( { map:gradTexture([[0.75,0.6,0.4,0.25], ['#1B1D1E','#3D4143','#72797D', '#b0babf']]), side:THREE.BackSide, depthWrite: false, fog:false }  ));
        //back.geometry.applyMatrix(new THREE.Matrix4().makeRotationZ(15*ToRad));
        scene.add( back );

        geoBox = new THREE.BoxGeometry( 1, 1, 1 );
        geoCyl = new THREE.CylinderGeometry( 0.5, 0.5, 1, 6, 1 );

        buffgeoSphere = new THREE.BufferGeometry();
        buffgeoSphere.fromGeometry( new THREE.SphereGeometry( 1 , 20, 10 ) );

        buffgeoBox = new THREE.BufferGeometry();
        buffgeoBox.fromGeometry( new THREE.BoxGeometry( 1, 1, 1 ) );

        matSphere = new THREE[materialType]( { color: 0x99999A, name:'sph' ,specular: 0xFFFFFF, shininess: 120, transparent: true, opacity: 0.9 } );
        matBox = new THREE[materialType]( {  color: 0xAA8058, name:'box' } );
        matSphereSleep = new THREE[materialType]( { color:  0x666667, name:'ssph', specular: 0xFFFFFF, shininess: 120 , transparent: true, opacity: 0.7} );
        matBoxSleep = new THREE[materialType]( {  color: 0x383838, name:'sbox' } );
        matGround = new THREE.MeshLambertMaterial( { color: 0x3D4143, transparent:true, opacity:0.5 } );

        // events

        window.addEventListener( 'resize', onWindowResize, false );

        // physics

        initOimoPhysics();

    }

    function loop() {
       
        updateOimoPhysics();
        renderer.render( scene, camera );
        requestAnimationFrame( loop );

    }

    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize( window.innerWidth, window.innerHeight );

    }

    function addStaticBox(size, position, rotation) {
        var mesh = new THREE.Mesh( buffgeoBox, matGround );
        mesh.scale.set( size[0], size[1], size[2] );
        mesh.position.set( position[0], position[1], position[2] );
        mesh.rotation.set( rotation[0]*ToRad, rotation[1]*ToRad, rotation[2]*ToRad );
        scene.add( mesh );
        grounds.push(mesh);
        mesh.castShadow = true;
        mesh.receiveShadow = true;
    }

    function initCapsuleGeometry (radius, height, SRadius, SHeight) {
        types = [ 'sphere', 'sphere','sphere'];
        //types = [ 'sphere', 'cylinder','sphere'];
        //sizes = [ radius,radius,radius, radius,height,radius, radius,radius,radius ];
        sizes = [ radius,radius,radius, radius,radius,radius, radius,radius,radius ];
        positions = [0,0,0,   0,height*0.5,0, 0,height,0];
        var sRadius = SRadius || 20;
        var sHeight = SHeight || 10;
        var o0 = Math.PI*2;
        var o1 = Math.PI/2;
        var g = new THREE.Geometry();
        var m0 = new THREE.CylinderGeometry(radius, radius, height, sRadius, 1, true);
        var m1 = new THREE.SphereGeometry(radius, sRadius, sHeight, 0, o0, 0, o1);
        var m2 = new THREE.SphereGeometry(radius, sRadius, sHeight, 0, o0, o1, o1);
        var mtx0 = new THREE.Matrix4().makeTranslation(0, 0,0);
        var mtx1 = new THREE.Matrix4().makeTranslation(0, height*0.5,0);
        var mtx2 = new THREE.Matrix4().makeTranslation(0, -height*0.5,0);
        g.merge( m0, mtx0);
        g.merge( m1, mtx1);
        g.merge( m2, mtx2);
        capsuleGeometry = new THREE.BufferGeometry();
        capsuleGeometry.fromGeometry(g);
    }

    /*function initCapsuleGeometry (radius, height, SRadius, SHeight) {
        types = [ 'sphere', 'sphere','sphere'];
        //types = [ 'sphere', 'cylinder','sphere'];
        //sizes = [ radius,radius,radius, radius,height,radius, radius,radius,radius ];
        sizes = [ radius,radius,radius, radius,radius,radius, radius,radius,radius ];
        //positions = [ 0,0,0,   0,height*0.5,0, 0,height,0 ];
        positions = [ 0,-height,0,   0,0,0, 0,height,0 ];
        var sRadius = SRadius || 20;
        var sHeight = SHeight || 10;
        var o0 = Math.PI*2;
        var o1 = Math.PI/2;
        var g = new THREE.Geometry();
        var m0 = new THREE.CylinderGeometry( radius, radius, height, sRadius, 1, true );
        var m1 = new THREE.SphereGeometry( radius, sRadius, sHeight, 0, o0, 0, o1);
        var m2 = new THREE.SphereGeometry( radius, sRadius, sHeight, 0, o0, o1, o1);
        var mtx0 = new THREE.Matrix4().makeTranslation(0, 0 ,0 );
        var mtx1 = new THREE.Matrix4().makeTranslation(0, height*0.5,0);
        var mtx2 = new THREE.Matrix4().makeTranslation(0, -height*0.5,0);
        g.merge( m0, mtx0);
        g.merge( m1, mtx1);
        g.merge( m2, mtx2);
        capsuleGeometry = new THREE.BufferGeometry();
        capsuleGeometry.fromGeometry( g );
    }*/

    function clearMesh(){
        var i=meshs.length;
        while (i--) scene.remove(meshs[ i ]);
        i = grounds.length;
        while (i--) scene.remove(grounds[ i ]);
        grounds = [];
        meshs = [];
    }

    //----------------------------------
    //  OIMO PHYSICS
    //----------------------------------

    function initOimoPhysics(){

        world = new OIMO.World( {info:true, worldscale:100,  broadphase:1 } );
        //initChairGeometry();
        initCapsuleGeometry(10,22,20,10);
        populate(2);
        //setInterval( updateOimoPhysics, 1000/60 );
    }

    function populate(n) {

        var max = document.getElementById("MaxNumber").value;

        var pos = [];

        if(n===1) type = 1
        else if(n===2) type = 2;
        //else if(n===3) type = 3;

        // reset old
        clearMesh();
        world.clear();
        bodys=[];

        var b;

        if(type===1){// DEMO 1
            //add ground
        var ground0 = world.add({size:[40, 40, 390], pos:[-180,20,0], world:world});
        var ground1 = world.add({size:[40, 40, 390], pos:[180,20,0], world:world});
        var ground2 = world.add({size:[400, 80, 400], pos:[0,-40,0], world:world});

        addStaticBox([40, 40, 390], [-180,20,0], [0,0,0]);
        addStaticBox([40, 40, 390], [180,20,0], [0,0,0]);
        addStaticBox([400, 80, 400], [0,-40,0], [0,0,0]);

            var i = max;
            var j;

            while (i--){
                pos[1] = 100 + Math.random()*1000;
                pos[0] = -100 + Math.random()*200;
                pos[2] = -100 + Math.random()*200;

                bodys[i] = world.add({
                    type:types,
                    size:sizes,
                    pos:pos,
                    posShape:positions,
                    move:true, 
                    name:'box'+i, 
                    //config:[0.2, 0.4,0.1]
                });

                j = Math.round(Math.random()*2);

                if(j===1)meshs[i] = new THREE.Mesh( capsuleGeometry, matBox );
                else meshs[i] = new THREE.Mesh( capsuleGeometry, matSphere );

                meshs[i].castShadow = true;
                meshs[i].receiveShadow = true;

                scene.add(meshs[i]);
            }
        } else if(type===2){// DEMO 2
            var ground = world.add({size:[1000, 40, 1000], pos:[0,-20,0]});
            addStaticBox([1000, 40, 1000], [0,-20,0], [0,0,0]);
            var ground2 = world.add({size:[400, 40, 400], pos:[0,130,-600], rot:[45,0,0] });
            addStaticBox([400, 40, 400], [0,130,-600], [45,0,0]);

            var i = max;
            var j, k=0, l=0;
            

            while (i--){
                pos[1] = 50;
                pos[0] = -400+(50*l);
                pos[2] = -400+(50*k);

                l++;
                if(l>16){k++; l=0}

                bodys[i] = world.add({
                    type:types,
                    size:sizes,
                    pos:pos,
                    posShape:positions,
                    move:true, 
                    name:'box'+i, 
                    //config:[0.2,0.4,0.1]
                });

                j = Math.round(Math.random()*2);

                if(j===1)meshs[i] = new THREE.Mesh( capsuleGeometry, matBox );
                else meshs[i] = new THREE.Mesh( capsuleGeometry, matSphere );

                meshs[i].castShadow = true;
                meshs[i].receiveShadow = true;

                scene.add(meshs[i]);
            }

            bodys[max] = world.add({type:'sphere', size:[80], pos:[0,1000,-600], move:true, world:world});
            meshs[max] = new THREE.Mesh( buffgeoSphere, matSphere );
            meshs[max].scale.set( 80, 80, 80 );
            scene.add(meshs[max]);

            meshs[max].castShadow = true;
            meshs[max].receiveShadow = true;

        } 
    }

    function updateOimoPhysics() {

        if(world==null) return;

        // update world
        world.step();

        var x, y, z;
        var mesh, body;

        var i = bodys.length;
        while (i--){
            body = bodys[i];
            mesh = meshs[i];

            if(!body.sleeping){

                // apply physics mouvement
                mesh.position.copy(body.getPosition());
                mesh.quaternion.copy(body.getQuaternion());

                // change material
                if(mesh.material.name === 'sbox') mesh.material = matBox;
                if(mesh.material.name === 'ssph') mesh.material = matSphere; 

                // reset position
                if(mesh.position.y<-100){
                    x = -100 + Math.random()*200;
                    z = -100 + Math.random()*200;
                    y = 100 + Math.random()*1000;
                    body.resetPosition(x,y,z);
                }
            } else {
                if(mesh.material.name === 'box') mesh.material = matBoxSleep;
                if(mesh.material.name === 'sph') mesh.material = matSphereSleep;
            }
        }

        infos.innerHTML = world.getInfo();
        
    }

    function gravity(g){
        nG = document.getElementById("gravity").value
        world.gravity = new OIMO.Vec3(0, nG, 0);
    }

    //----------------------------------
    //  TEXTURES
    //----------------------------------

    function gradTexture(color) {
        var c = document.createElement("canvas");
        var ct = c.getContext("2d");
        c.width = 16; c.height = 256;
        var gradient = ct.createLinearGradient(0,0,0,256);
        var i = color[0].length;
        while(i--){ gradient.addColorStop(color[0][i],color[1][i]); }
        ct.fillStyle = gradient;
        ct.fillRect(0,0,16,256);
        var texture = new THREE.Texture(c);
        texture.needsUpdate = true;
        return texture;
    }

</script>
</body> 
</html>
